﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Diagnostics;

namespace DealerJudge.Core
{
    public class Logger : ILogger
    {
        private readonly log4net.ILog _logger;
        private const string Textseparator = "------------------------------------";

        public Logger(log4net.ILog log)
        {
            _logger = log;
        }

        public bool IsDebugEnabled
        {
            get { return _logger.IsDebugEnabled; }
        }

        public bool IsErrorEnabled
        {
            get { return _logger.IsErrorEnabled; }
        }

        public bool IsFatalEnabled
        {
            get { return _logger.IsFatalEnabled; }
        }

        public bool IsInfoEnabled
        {
            get { return _logger.IsInfoEnabled; }
        }

        public bool IsWarnEnabled
        {
            get { return _logger.IsWarnEnabled; }
        }

        public void Debug(object message)
        {
            PrepareSourceClassDetails();
            _logger.Debug(message);
        }

        public void Info(object message)
        {
            PrepareSourceClassDetails();
            _logger.Info(message);
        }

        public void Warn(object message)
        {
            PrepareSourceClassDetails();
            _logger.Warn(message);
        }

        public void Error(object message)
        {
            PrepareSourceClassDetails();
            _logger.Error(message);
        }

        public void Fatal(object message)
        {
            PrepareSourceClassDetails();
            _logger.Fatal(message);
        }

        public void Debug(Exception exception)
        {
            string exceptionMessage = ParseException(exception);
            PrepareSourceClassDetails();
            _logger.Debug(exceptionMessage);
        }

        public void Info(Exception exception)
        {
            string exceptionMessage = ParseException(exception);
            PrepareSourceClassDetails();
            _logger.Info(exceptionMessage);
        }


        public void Warn(Exception exception)
        {
            string exceptionMessage = ParseException(exception);
            PrepareSourceClassDetails();
            _logger.Warn(exceptionMessage);
        }

        public void Error(Exception exception)
        {
            string exceptionMessage = ParseException(exception);
            PrepareSourceClassDetails();
            _logger.Error(exceptionMessage);
        }

        public void Fatal(Exception exception)
        {
            string exceptionMessage = ParseException(exception);
            PrepareSourceClassDetails();
            _logger.Fatal(exceptionMessage);
        }

        private string ParseException(Exception exception)
        {
            StringBuilder exceptionInfo = new StringBuilder();
            Exception currentException;

            try
            {
                currentException = exception;
                int exceptionCount = 1;
                do
                {
                    exceptionInfo.AppendFormat("{0}{0}{1}) Exception {0}{2}", Environment.NewLine, exceptionCount, Textseparator);
                    exceptionInfo.AppendFormat("{0}Exception Type: {1}", Environment.NewLine, currentException.GetType().FullName);

                    PropertyInfo[] publicProperties = currentException.GetType().GetProperties();

                    foreach (PropertyInfo propInfo in publicProperties)
                    {
                        if (propInfo.Name != "InnerException" && propInfo.Name != "StackTrace")
                        {
                            if (propInfo.GetValue(currentException, null) == null)
                            {
                                exceptionInfo.AppendFormat("{0}{1}: NULL", Environment.NewLine, propInfo.Name);
                            }
                            else
                            {
                                exceptionInfo.AppendFormat("{0}{1}: {2}", Environment.NewLine, propInfo.Name, propInfo.GetValue(currentException, null));
                            }
                        }
                    }

                    if (currentException.StackTrace != null)
                    {
                        exceptionInfo.AppendFormat("{0}{0}StackTrace {0}{1}", Environment.NewLine, null);
                        exceptionInfo.AppendFormat("{0}{1}", Environment.NewLine, currentException.StackTrace);
                    }

                    currentException = currentException.InnerException;
                    exceptionCount++;
                } while (currentException != null);

                exceptionInfo.AppendFormat("{0}{1}", Environment.NewLine, Textseparator);

            }
            catch (Exception exobj)
            {
                _logger.Fatal(exobj.ToString());
            }
            return exceptionInfo.ToString();
        }

        private static void PrepareSourceClassDetails()
        {
            StackTrace stack = new StackTrace();
            StackFrame frame = stack.GetFrame(2);
            //This property will be get used in Log4Net config file as part of PatternLayout definition
            //to get source class details from which logger method has been invoked.
            log4net.ThreadContext.Properties["SourceClass"] = frame.GetMethod().DeclaringType + "." + frame.GetMethod().Name;
        }

    }
}
